package cn.web.web_module.service.impl;

import cn.itcast.mapper.accountMapper;
import cn.itcast.mapper.horsemanMapper;
import cn.itcast.mapper.orderMapper;
import cn.itcast.mapper.rechargeMapper;
import cn.itcast.pojo.*;
import cn.itcast.service.impl.orderServiceImpl;
import cn.itcast.util.DoubleUtils;
import cn.itcast.util.ResponseEntity;
import cn.web.web_module.entity.WithdrawRechargeInfo;
import cn.web.web_module.mapper.WithdrawRechargeInfoMapper;
import cn.web.web_module.service.RechargeService;
import cn.wx.MyConfig;
import cn.wx.WXPay;
import cn.wx.WXPayConfig;
import cn.wx.WXPayUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static cn.itcast.util.OrderNumber.getOrderIdByTime;

/**
 * @Author: 张松
 * @Description:
 * @Date: Created in 15:29 2021/2/24
 * @Modified By:
 */
@Slf4j
@Service
public class RechargeImpl implements RechargeService {



    @Resource
    private StringRedisTemplate stringRedisTemplate;


    @Resource
    private orderServiceImpl orderService;

    @Resource
    private rechargeMapper rechargeMapper;

    @Resource
    private horsemanMapper horsemanMapper;

    @Resource
    private WithdrawRechargeInfoMapper withdrawRechargeInfoMapper;

    @Resource
    private orderMapper orderMapper;

    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private RabbitTemplate rabbitTemplate;

    @Resource
    private accountMapper accountMapper;

    /**
     *
     * @Description: 用户充值
     *
     * @auther: 张松
     * @date: 16:06 2021/2/24
     * @param: [userRechargeInfo]
     * @return: cn.itcast.util.ResponseEntity
     *
     */

    @Override
    public ResponseEntity horsemanRechargeService(Map<String,String> userRechargeInfo,WXPayConfig myConfig) {
            String totalFee = userRechargeInfo.get("totalFee"); //用户需要充值的金额
            String openId = userRechargeInfo.get("openId"); //用户的openid
            String name = userRechargeInfo.get("name"); //用户的姓名
            Map<String, String> stringStringMap=null;
            Map<String,String> stringXml=null;
            ResponseEntity responseEntity = ifRecharge(totalFee, openId, name);
            if (responseEntity.getCode() != 200) {
                return responseEntity;
            }
            //判断是否可以支付
            Map<String, String> unifiedOrderMap = createUnifiedOrderMap(totalFee, openId);
            try {
                stringXml = getWxPay(myConfig).unifiedOrder(unifiedOrderMap); //api返回参数
            } catch (Exception e) {
                log.error("统一下单接口调用失败");
                e.printStackTrace();
            }
            if (stringXml.get("return_code").equals("SUCCESS") && stringXml.get("result_code").equals("SUCCESS")) {
                stringStringMap = disposeStringXml(stringXml);
                //处理api返回参数,并返回小程序wx.requestPayment所需参数
            }
            if (!createRechargeTable(openId, totalFee, name, unifiedOrderMap)) {
                return new ResponseEntity(300, "生成充值表失败");
            }
            return new ResponseEntity(200,"下单成功",stringStringMap);

    }


    /**
     *
     * @Description: mysql写法生成充值
     *
     * @auther: 张松
     * @date: 18:58 2021/3/29
     * @param: [openId, totalFee, name, map]
     * @return: boolean
     *
     */
    private boolean createRechargeTable(String openId, String totalFee, String name,Map<String,String> map) {
        //生成业务充值记录订单
        recharge recharge = new recharge();
        recharge.setOpenId(openId);
        recharge.setName(name);
        recharge.setRechargeTime(new Date());
        recharge.setRechargeSum(Double.valueOf(totalFee)/100);
        recharge.setRechargeNumber(map.get("out_trade_no"));
        recharge.setPayNumber(map.get("prepay_id"));
        recharge.setPayType("微信支付");
        recharge.setPayState("未支付");
        recharge.setBillState("未入账");
        boolean ifCreateSuccess = orderService.addRecharge(recharge);
        return ifCreateSuccess;
    }





    /**
     *
     * @Description: 处理api返回参数,并返回小程序所需函数
     *
     * @auther: 张松
     * @date: 11:46 2021/2/25
     * @param: [stringXml]
     * @return: java.util.Map<java.lang.String,java.lang.String>
     *
     */
    private Map<String,String> disposeStringXml(Map<String, String> stringXml) {
            Map<String,String> paySignParameter = new HashMap<>();
            paySignParameter.put("appId",stringXml.get("appid"));
            paySignParameter.put("nonceStr",WXPayUtil.generateNonceStr());
            paySignParameter.put("package","prepay_id="+stringXml.get("prepay_id"));
            paySignParameter.put("signType","MD5");
            paySignParameter.put("timeStamp",System.currentTimeMillis() / 1000+"");
            String paySign=null;
            try {
                paySign = WXPayUtil.generateSignature(paySignParameter, new MyConfig().getKey());
            } catch (Exception e) {
                e.printStackTrace();
            }
            paySignParameter.put("paySign",paySign);
            paySignParameter.remove("appId");
        return paySignParameter;
    }


    /**
     *
     * @Description: 获取wxPay
     *
     * @auther: 张松
     * @date: 9:53 2021/2/25
     * @param: []
     * @return: cn.wx.WXPay
     *
     */
    private WXPay getWxPay(WXPayConfig MyConfig) {
        WXPay wxPay=null;
        try {
            wxPay = new WXPay(MyConfig);
        } catch (Exception e) {
            e.printStackTrace();
            log.info("error:WXPay创建失败");
        }

        return wxPay;
    }



//    private WXPay getWxPay() {
//        WXPay wxPay=null;
//        try {
//            wxPay = new WXPay(new MyConfig());
//        } catch (Exception e) {
//            e.printStackTrace();
//            log.info("error:WXPay创建失败");
//        }
//
//        return wxPay;
//    }


    /**
     *
     * @Description: 创建统一下单参数MAp
     *
     * @auther: 张松
     * @date: 9:42 2021/2/25
     * @param: [totalFee]
     * @return: java.util.Map<java.lang.String,java.lang.String>
     *
     */
    private Map<String, String> createUnifiedOrderMap(String totalFee,String openId) {
        String spbill_create_ip = null; //本机Ip地址
        try {
            spbill_create_ip = InetAddress.getLocalHost().getHostAddress();
        } catch (UnknownHostException e) {
            e.printStackTrace();
            log.info("error:获取终端IP失败");
        }
        Map<String,String> unifiedOrderMap = new HashMap<>();
        unifiedOrderMap.put("body","账户充值");
        unifiedOrderMap.put("out_trade_no",WXPayUtil.generateNonceStr());
//        unifiedOrderMap.put("total_fee", (Integer.parseInt(totalFee)/100)+"");
        unifiedOrderMap.put("total_fee", totalFee);
        unifiedOrderMap.put("spbill_create_ip",spbill_create_ip);
        unifiedOrderMap.put("notify_url","https://www.dhnep.cn:443/Recharge/RechargeNotifyUrl");
//        unifiedOrderMap.put("notify_url","http://66qvgh.natappfree.cc/Recharge/RechargeNotifyUrl");
        unifiedOrderMap.put("trade_type","JSAPI");
        unifiedOrderMap.put("openid",openId);
        System.out.println("unifiedOrderMap:"+unifiedOrderMap);
        return unifiedOrderMap;
    }

    /**
     *
     * @Description: 判断用户支付
     *
     * @auther: 张松
     * @date: 18:10 2021/2/24
     * @param: [totalFee, openId]
     * @return: cn.itcast.util.ResponseEntity
     *
     */
    private ResponseEntity ifRecharge(String totalFee, String openId,String name) {
        if (!ifNUllAndZero(totalFee,openId,name)){
            return new ResponseEntity(300,"参数不合法");
        }
        //判断参数不能为空
        if (!ifIsRecharge(openId,totalFee)){
            return new ResponseEntity(300,"正在支付中,请稍后");
        }
        //判断用户是否正在支付
        return new ResponseEntity(200,"可以支付");
    }

    /**
     *
     * @Description: 判断参数不为空不为0不为null
     *
     * @auther: 张松
     * @date: 18:16 2021/2/24
     * @param: [totalFee, openId, name]
     * @return: boolean
     *
     */
    private boolean ifNUllAndZero(String totalFee, String openId, String name) {
        if (StringUtils.isNotBlank(totalFee)&&StringUtils.isNotBlank(openId)&&StringUtils.isNotBlank(name)){
            if (!totalFee.equals("0")){
            return true;
            }
        }
        return false;
    }


    /**
     *
     * @Description:判断用户是否正在支付
     *
     * @auther: 张松
     * @date: 18:09 2021/2/24
     * @param: [openId, totalFee]
     * @return: boolean
     *
     */
    private boolean ifIsRecharge(String openId,String totalFee) {
        Boolean ifAbsent = stringRedisTemplate.opsForValue().setIfAbsent("Recharge:" + openId, openId + ":" + totalFee);
        stringRedisTemplate.expire("Recharge:"+openId,1, TimeUnit.MINUTES);
        return ifAbsent;
    }


    /**
     *
     * @Description: 验证微信回调函数
     *
     * @auther: 张松
     * @date: 11:56 2021/2/26
     * @param: [httpServletRequest]
     * @return: cn.itcast.util.ResponseEntity
     *
     */
    @Override
    public ResponseEntity RechargeNotifyUrl(HttpServletRequest httpServletRequest) {
        log.info("订单支付开始");
        Map<String,String> notifyUrlParameter=null;
        try {
        notifyUrlParameter=createParameter(httpServletRequest);  //解析微信支付回调函数并且返回一个Map
        if (ifPaySuccess(notifyUrlParameter)){
            return new ResponseEntity(300,"该订单已经充值,请查看账户");
        }
        //判断是否已经支付过
        if (notifyUrlParameter.get("return_code").equals("FAIL")||notifyUrlParameter.get("result_code").equals("FAIL")){
            return new ResponseEntity(300,"微信支付回调失败");
        } //判断是否回调成功
        if(!ifSign(notifyUrlParameter)){
            return new ResponseEntity(300,"数据核对失误");
        }//验证微信回调的sign签名和参数生成的sign签名是否一样,防止数据被黑客修改
        if (!updateRecharge(notifyUrlParameter)){
            return new ResponseEntity(300,"充值状态修改失败");
        }//给充值表recharge修改已充值状态
        if(!addUserAccount(notifyUrlParameter)){
            return new ResponseEntity(300,"账户余额添加失败");
        }  //给用户账户添加账户余额并在earning表中记录数据
         if (!addEarningInfo(notifyUrlParameter)){
             return new ResponseEntity(300,"账户余额添加失败");
         } //在输入表中记录充值数据
        if (!addRechargeInfo(notifyUrlParameter)){
            return new ResponseEntity(300,"增加withdraw_recharge_info信息失败");
        }
        log.info(notifyUrlParameter.get("openid")+"充值成功,金额为:"+notifyUrlParameter.get("total_fee"));
        return new ResponseEntity(200,"微信支付回调成功");
        }finally {
            if (StringUtils.isNotBlank(stringRedisTemplate.opsForValue().get("Recharge:" + notifyUrlParameter.get("openid")))){
                stringRedisTemplate.delete("Recharge:" + notifyUrlParameter.get("openid"));
                log.info("订单支付删除redis");
            }
        }
    }


    /**
     *
     * @Description: 给充值表recharge修改已充值状态
     *
     * @auther: 张松
     * @date: 18:29 2021/3/31
     * @param: [notifyUrlParameter]
     * @return: boolean
     *
     */
    private boolean updateRecharge(Map<String, String> notifyUrlParameter) {
        List<recharge> recharges = rechargeMapper.selectRechargeNumber(notifyUrlParameter.get("out_trade_no"));
        if (recharges.isEmpty()||recharges.size()<=0){
            return false;
        }
        recharge recharge = recharges.get(0);

        account account = accountMapper.selectByAccountOpenid(recharge.getOpenId());
        Double balance = account.getAccountMoneyBalance(); //获取用户充值之前的余额
        log.debug(account.getAccountName() + "充值之前的金额为" + balance );
        Double rechargeSum = recharge.getRechargeSum(); //本次充值的金额
        double sum = DoubleUtils.add(balance, rechargeSum); //充值之后的金额
        log.debug(account.getAccountName() + "充值之后的总金额为：" + sum);

        recharge.setPayState("已支付");
        recharge.setBillState("已入账");
        recharge.setBillTime(new Date());
        recharge.setCountnum(sum);
        int i = rechargeMapper.updateByPrimaryKeySelective(recharge);
        if (i>0){
            return true;
        }
        return false;
    }

    /**
     *
     * @Description: 增加用户余额并在earning表中记录数据
     *
     * @auther: 张松
     * @date: 17:56 2021/3/31
     * @param: [notifyUrlParameter]
     * @return: boolean
     *
     */
    private boolean addUserAccount(Map<String, String> notifyUrlParameter) {
        String openid = notifyUrlParameter.get("openid");
        account account = accountMapper.selectByAccountOpenid(openid);
        if (account==null){
            return false;
        }
        double total_fee = Double.parseDouble(notifyUrlParameter.get("total_fee"))/100;
        account.setAccountMoneyBalance(account.getAccountMoneyBalance()+total_fee);
        account.setAccountMoneyRental(account.getAccountMoneyRental()+total_fee);
        int i = accountMapper.updateByPrimaryKeySelective(account);
        log.info(account.getAccountName()+": 充值 :"+total_fee + "元");
        if (i>0){
            return true;
        }
        return false;
    }


    /**
     *
     * @Description: 使用rabbitmq发送earning消息记录到表中
     *
     * @auther: 张松
     * @date: 18:42 2021/3/31
     * @param: [account]
     * @return: void
     *
     */
    private boolean addEarningInfo(Map<String,String> notifyUrlParameter) {
        String exchange = "direct_EarningInfo_exchange";
        String routingKey= "earningInfo";
        rabbitTemplate.convertAndSend(exchange,routingKey,notifyUrlParameter);

        return true;
    }




    /**
     *
     * @Description: 正常在mysql中输入WithdrawRechargeInfo消息
     *
     * @auther: 张松
     * @date: 17:08 2021/3/30
     * @param: [notifyUrlParameter]
     * @return: boolean
     *
     */
//    private boolean addRechargeInfo(Map<String, String> notifyUrlParameter) {
//
//        String openid = notifyUrlParameter.get("openid");
//        List<horseman> horsemen = horsemanMapper.selectHorsemanOpenId(openid);
//        if (horsemen.size()<=0||horsemen.isEmpty()){
//            return true;
//        }
//        List<order> orders = orderMapper.selectHorsemanStocksOrder(openid);
//        Integer orderId=0;
//        if (orders.size()>0||!orders.isEmpty()){
//            orderId=orders.get(0).getId();
//        }
//        WithdrawRechargeInfo withdrawRechargeInfo = new WithdrawRechargeInfo();
//        withdrawRechargeInfo.setRechargeMoney(Long.parseLong(notifyUrlParameter.get("total_fee")));
//        withdrawRechargeInfo.setRechargeNumber(notifyUrlParameter.get("out_trade_no"));
//        withdrawRechargeInfo.setHorsemanName(horsemen.get(0).getHorsemanName());
//        withdrawRechargeInfo.setHorsemanAccount(openid);
//        withdrawRechargeInfo.setRechargeTime(new Date());
//        withdrawRechargeInfo.setOrderId(orderId);
//        log.info(horsemen.get(0).getHorsemanName()+":"+openid+"记录withdrawRechargeInfo"+"充值了:"+notifyUrlParameter.get("total_fee")+"元");
//        int i = withdrawRechargeInfoMapper.insertSelective(withdrawRechargeInfo);
//        if (i>0){
//            log.info(horsemen.get(0).getHorsemanName()+":"+openid+"记录withdrawRechargeInfo成功"+"充值了:"+notifyUrlParameter.get("total_fee")+"元");
//            return true;
//        }
//        return false;
//    }




    /**
     *
     * @Description: 使用rabbitmq异步发送消息
     *
     * @auther: 张松
     * @date: 17:09 2021/3/30
     * @param: [notifyUrlParameter]
     * @return: boolean
     *
     */
    private boolean addRechargeInfo(Map<String, String> notifyUrlParameter) {
        String exchange = "direct_RechargeInfo_exchange";
        String routingKey= "rechargeInfo";
        rabbitTemplate.convertAndSend(exchange,routingKey,notifyUrlParameter);
        return true;
    }








    /**
     *
     * @Description: 判断是否已经支付过
     *
     * @auther: 张松
     * @date: 15:29 2021/2/26
     * @param: [notifyUrlParameter]
     * @return: boolean
     *
     */
    private boolean ifPaySuccess(Map<String, String> notifyUrlParameter) {
        String out_trade_no = notifyUrlParameter.get("out_trade_no");
        List<recharge> recharges = rechargeMapper.selectRechargeNumber(out_trade_no);
        if (recharges.get(0).getPayState().equals("已支付")&&recharges.get(0).getBillState().equals("已入账")){
            return true;
        }
        return false;
    }

    /**
     *
     * @Description: 验证微信回调的sign签名和参数生成的sign签名是否一样, 防止数据被黑客修改
     *
     * @auther: 张松
     * @date: 11:55 2021/2/26
     * @param: [notifyUrlParameter]
     * @return: boolean
     *
     */
    private boolean ifSign(Map<String, String> notifyUrlParameter) {
        String sign = notifyUrlParameter.get("sign");
        notifyUrlParameter.remove("sign");
        String ifSign=null;
        try {
            ifSign = WXPayUtil.generateSignature(notifyUrlParameter, new MyConfig().getKey());
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (ifSign.equals(sign)){
            return true;
        }
        return false;
    }
    /**
     *
     * @Description: 修改充值表和增加充值用户余额
     *
     * @auther: 张松
     * @date: 15:04 2021/2/26
     * @param: [notifyUrlParameter]
     * @return: boolean
     *
     */
//    private boolean addUserAccount(Map<String, String> notifyUrlParameter) {
//        recharge recharge = new recharge();
//        recharge.setPayState("已支付");
//        recharge.setBillState("已入账");
//        recharge.setBillTime(new Date());
//        recharge.setRechargeNumber(notifyUrlParameter.get("out_trade_no"));
//        boolean isupdate = orderService.updateRecharge(recharge);
//        if (isupdate){
//            return true;
//        }
//        return false;
//    }




    /**
     *
     * @Description: 解析微信支付回调函数并且返回一个Map
     * 
     * @auther: 张松
     * @date: 11:55 2021/2/26
     * @param: [httpServletRequest]
     * @return: java.util.Map
     *
     */
    private Map createParameter(HttpServletRequest httpServletRequest) {
        String postStr = WXPayUtil.getPostStr(httpServletRequest);
        Map<String, String> stringStringMap=null;
        try {
            stringStringMap = WXPayUtil.xmlToMap(postStr);
        } catch (Exception e) {
            log.error("解析微信回调函数失败");
            e.printStackTrace();
        }
        return stringStringMap;
    }




    /**
     *
     * @Description: 用户取消支付删除redis中用户的数据
     *
     * @auther: 张松
     * @date: 16:45 2021/2/27
     * @param: [horsemanOpenid]
     * @return: boolean
     *
     */

    @Override
    public boolean deleteRedisHorsemanPay(Map<String, String> horsemanOpenid) {
        String openId = horsemanOpenid.get("openId");
        if (!stringRedisTemplate.opsForValue().get("Recharge:" + openId).isEmpty()){
            stringRedisTemplate.delete("Recharge:" + openId);
            return true;
        }
        return false;
    }

}
